// Copyright 2022 The Molego Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package handle

import (
	"strings"
	"time"

	config "gitee.com/west0207/molego/core/config"
	db "gitee.com/west0207/molego/core/db"
	. "gitee.com/west0207/molego/core/log"
	utils "gitee.com/west0207/molego/core/utils"

	"xorm.io/xorm"

	etree "gitee.com/west0207/etree"

	translate "gitee.com/west0207/molego/core/translate"
)

const META_CHANGE_SET = `
<changeSet>
	<createTable tableName="db_change_file" remarks="changeLog file">
		<column name="id" type="varchar(100)" remarks="primary key is the file name">
			<constraints primaryKey="true" nullable="false" primaryKeyName="pk_db_change_file" />
		</column>
		<column name="created_time" type="varchar(20)" remarks="record created time" />
		<column name="file_sign" type="varchar(100)" remarks="file sha256 sum" />
		<column name="file_path" type="varchar(150)" remarks="file path" />
		<column name="file_type" type="varchar(20)" remarks="file type" defaultValue="xml" />
		<column name="executed_time" type="varchar(20)" remarks="last executed time" />
		<column name="executed_status" type="varchar(36)" remarks="last executed status, [success, failure]" />
		<column name="entry_file" type="varchar(60)" remarks="entry file name" />
	</createTable>
	<createTable tableName="db_change_set" remarks="changeSet status">
		<column name="id" type="varchar(100)" remarks="primary key is the changeSet id">
			<constraints primaryKey="true" nullable="false" primaryKeyName="pk_db_change_set" />
		</column>
		<column name="author" type="varchar(100)" remarks="author" />
		<column name="file_name" type="varchar(100)" remarks="filename" />
		<column name="created_time" type="varchar(20)" remarks="record created time" />
		<column name="executed_time" type="varchar(20)" remarks="last executed time" />
		<column name="executed_status" type="varchar(36)" remarks="last executed status, [success, failure]" />
		<column name="executed_order" type="decimal(7)" remarks="executed order" />
		<column name="exec_type" type="varchar(20)" remarks="exec type, [executed,reran]" />
		<column name="changeset_comment" type="varchar(500)" remarks="changeset comment" />
		<column name="changeset_sign" type="varchar(100)" remarks="changeset sha256 sum" />
		<column name="liquigo_version" type="varchar(20)" remarks="liquigo version" />
	</createTable>
</changeSet>
`

// type DbChangeFile struct {
// 	Id             sql.NullString
// 	CreatedTime    sql.NullString
// 	FileSign       sql.NullString
// 	FilePath       sql.NullString
// 	FileType       sql.NullString
// 	ExecutedTime   sql.NullString
// 	ExecutedStatus sql.NullString
// 	EntryFile      sql.NullString
// }

// type DbChangeSet struct {
// 	Id               sql.NullString
// 	Author           sql.NullString
// 	FileName         sql.NullString
// 	CreatedTime      sql.NullString
// 	ExecutedTime     sql.NullString
// 	ExecutedStatus   sql.NullString
// 	ExecutedOrder    sql.NullInt16
// 	ExecType         sql.NullString
// 	ChangesetComment sql.NullString
// 	ChangesetSign    sql.NullString
// 	LiquigoVersion   sql.NullString
// }

type DbChangeFile struct {
	Id             string `xorm:"pk"`
	CreatedTime    string
	FileSign       string
	FilePath       string
	FileType       string
	ExecutedTime   string
	ExecutedStatus string
	EntryFile      string
}

type DbChangeSet struct {
	Id               string `xorm:"pk"`
	Author           string
	FileName         string
	CreatedTime      string
	ExecutedTime     string
	ExecutedStatus   string
	ExecutedOrder    int
	ExecType         string
	ChangesetComment string
	ChangesetSign    string
	LiquigoVersion   string
}

// func HandleMetaTable(dbmsName *string, dbConn *sql.DB) error {
// 	rows, err := selectDbChangeFile(dbConn)
// 	// fmt.Printf("rows: %v\n", rows)
// 	// selectSql := "select * from dbchangelogfile;"
// 	// rows, err := dbConn.Query(selectSql)
// 	if err != nil {
// 		Sug.Errorf("select err: %v", err)
// 		// if err = createTable(dbmsName, dbConn); err != nil {
// 		// 	fmt.Printf("createTable err %v\n", err)
// 		// }
// 		return err
// 	}
// 	defer rows.Close()

// 	dbChangeFiles := make([]DbChangeFile, 0, 10)
// 	rowFile := DbChangeFile{}
// 	for rows.Next() {
// 		// err := rows.Scan(&id, &created_time, &file_sign, &file_path, //
// 		// 	&file_type, &executed_time, &executed_status, &entry_file)
// 		err := rows.Scan(&rowFile.Id, &rowFile.CreatedTime, &rowFile.FileSign, &rowFile.FilePath, //
// 			&rowFile.FileType, &rowFile.ExecutedTime, &rowFile.ExecutedStatus, &rowFile.EntryFile)
// 		if err != nil {
// 			Sug.Errorf("rows.Scan err %v", err)
// 			panic(err)
// 		}
// 		// log.Println(rowFile)
// 		dbChangeFiles = append(dbChangeFiles, rowFile)
// 		// log.Println(id.Valid, created_time.String, file_sign.String, file_path.String, //
// 		// 	file_type.String, executed_time.String, executed_status.String, entry_file.Valid)
// 	}

// 	Sug.Info("dbChangeFiles: ", dbChangeFiles)
// 	Sug.Info("rows.Next() over")

// 	if err = rows.Err(); err != nil {
// 		Sug.Errorf("rows.Err() err: %v", err)
// 		return err
// 	}

// 	return nil
// }

// 查询当前最大值执行排序值executed_order
func SelectMaxExecutedOrder() int {
	// has, err := db.Engine.Where("id = ?", *changeSetId).Get(&dbChangeSet)
	// Sug.Infof("----- has %v, dbChangeSet %v", has, dbChangeSet)

	// var dbChangeSet = DbChangeSet{}
	// maxOrder01, err1 := db.Engine.Max(&dbChangeSet, "executed_order")
	// Sug.Infof("----- maxOrder01 %v, err1 %v", maxOrder01, err1)

	selectSql := "select max(executed_order) max_order from db_change_set"
	// results, err := db.Engine.Query(selectSql)
	var maxOrder int
	_, err := db.Engine.SQL(selectSql).Get(&maxOrder)
	if err != nil {
		// sql.ErrNoRows
		Sug.Errorf("select max(executed_order) err %v\nsql: %v\n", err, selectSql)
		return utils.INT_ZERO
	}
	return maxOrder

	// maxOrder, _ := strconv.Atoi(string(results[utils.INT_ZERO]["max_order"]))
	// Sug.Infof("----- results[utils.INT_ZERO][max_order]) bb %v", bb)
	// for _, v := range results {
	// 	aa, _ := strconv.Atoi(string(v["max_order"]))
	// 	Sug.Infof("----- int(v[max_order]) v %v", aa)
	// }
	// return maxOrder

	// selectSql := "select max(executed_order) max_order from db_change_set"
	// var maxOrder sql.NullInt32
	// err := dbConn.QueryRow(selectSql).Scan(&maxOrder)
	// if err != nil {
	// 	// sql.ErrNoRows
	// 	Sug.Errorf("select max(executed_order) err %v\nsql: %v\n", err, selectSql)
	// 	return int(maxOrder.Int32)
	// }
	// return int(maxOrder.Int32)
}

// 根据id(changeLogXml文件名称)查询db_change_file表中对应的记录以确定是否需要运行
// 如果不存在或者签名值变更，则返回true，需要运行
// dbConn *sql.DB 该数据库连接实例
// id *string 指定的id，即changeLogXml文件名称的指针
// fileSum *string 该文件的签名值(sha256摘要值)
// return bool 是否需要运行
func CheckDbChangeFileById(id *string, fileSum *string) bool {
	dbChangeFile, err := SelectDbChangeFileById(id)
	if err != nil {
		// sql.ErrNoRows
		return true
	}
	if dbChangeFile.FileSign == *fileSum {
		// 文件没有变更，无需运行
		return false
	}
	return true
}

// 根据id(changeLogXml文件名称)查询db_change_file表中对应的记录并返回
// dbConn *sql.DB 该数据库连接实例
// fileName *string 指定的changeLogXml文件名称指针
func SelectDbChangeFileById(id *string) (*DbChangeFile, error) {
	dbChangeFile := DbChangeFile{}

	has, err := db.Engine.Where("id = ?", *id).Get(&dbChangeFile)
	Sug.Infof("----- has %v, dbChangeFile %v", has, dbChangeFile)
	if !has || err != nil {
		// sql.ErrNoRows
		return nil, err
	}
	return &dbChangeFile, nil

	// var selectSql string
	// switch DbConfig.DbmsName {
	// case translate.PostgreSQL, translate.Kingbase:
	// 	selectSql = "select * from db_change_file where id = $1"
	// case translate.Oracle:
	// 	selectSql = "select * from db_change_file where id = :1"
	// default:
	// 	selectSql = "select * from db_change_file where id = ?"
	// }
	// err := dbConn.QueryRow(selectSql, id).Scan( //
	// 	&dbChangeFile.Id, &dbChangeFile.CreatedTime, //
	// 	&dbChangeFile.FileSign, &dbChangeFile.FilePath, &dbChangeFile.FileType, //
	// 	&dbChangeFile.ExecutedTime, &dbChangeFile.ExecutedStatus, &dbChangeFile.EntryFile)
	// if err != nil {
	// 	// sql.ErrNoRows
	// 	// Sug.Errorf("select db_change_file err %v\nsql: %v\n", err, selectSql)
	// 	return nil, err
	// }
	// return &dbChangeFile, nil
}

// 根据id(changeLogXml文件名称)插入或更新db_change_file表
// dbConn *sql.DB 该数据库连接实例
// id *string 指定的id，即changeLogXml文件名称的指针
// fileSum *string 该文件的签名值(sha256摘要值)
// filePath *string 文件路径的指针
// entryFile *string 入口文件的指针
func UpdateDbChangeFileById(id *string, fileSum *string, //
	filePath *string, entryFile *string) {

	dbChangeFile := DbChangeFile{}
	has, err := db.Engine.Where("id = ?", *id).Get(&dbChangeFile)
	// Sug.Infof("----- has %v, dbChangeFile %v", has, dbChangeFile)
	nowFmt := time.Now().Format(utils.YMDHMS)
	if !has || err != nil {
		// 首次运行，插入新记录
		dbChangeFile = DbChangeFile{Id: *id, CreatedTime: nowFmt, FileSign: *fileSum, //
			FilePath: *filePath, FileType: "xml", ExecutedTime: nowFmt, ExecutedStatus: utils.SUCCESS, EntryFile: *entryFile}
		affected, err := db.Engine.Insert(&dbChangeFile)
		if err != nil {
			Sug.Errorf("insert into db_change_file failed, affected: %v, err: %v", affected, err)
			Sug.Errorf("dbChangeFile: %v", dbChangeFile)
			return
		}
		Sug.Infof("insert into db_change_file affected: %v, id: %v", affected, *id)
		return
	}

	// 再次运行，更新该记录
	// updateSql := `
	// 	update db_change_file
	// 	set file_sign = ?, executed_time = ?, executed_status = ?
	// 	where id = ?
	// `
	dbChangeFile = DbChangeFile{FileSign: *fileSum, ExecutedTime: nowFmt, ExecutedStatus: utils.SUCCESS}
	affected, err := db.Engine.ID(*id).Update(&dbChangeFile)
	// affected, err := db.Engine.Exec(updateSql, fileSum, nowFmt, utils.SUCCESS, id)
	if err != nil {
		Sug.Errorf("update db_change_file failed, affected: %v, err: %v", affected, err)
		Sug.Errorf("dbChangeFile.id: %v", *id)
		return
	}
	Sug.Infof("update db_change_file affected: %v, id = %v", affected, *id)

	// dbChangeFile := DbChangeFile{}
	// var selectSql string
	// switch DbConfig.DbmsName {
	// case translate.PostgreSQL, translate.Kingbase:
	// 	selectSql = "select * from db_change_file where id = $1"
	// case translate.Oracle:
	// 	selectSql = "select * from db_change_file where id = :1"
	// default:
	// 	selectSql = "select * from db_change_file where id = ?"
	// }
	// err := dbConn.QueryRow(selectSql, id).Scan( //
	// 	&dbChangeFile.Id, &dbChangeFile.CreatedTime, //
	// 	&dbChangeFile.FileSign, &dbChangeFile.FilePath, &dbChangeFile.FileType, //
	// 	&dbChangeFile.ExecutedTime, &dbChangeFile.ExecutedStatus, &dbChangeFile.EntryFile)

	// nowFmt := time.Now().Format(utils.YMDHMS)
	// if err != nil {
	// 	// sql.ErrNoRows

	// 	// 首次运行，插入新记录
	// 	var insertSql string
	// 	switch DbConfig.DbmsName {
	// 	case translate.PostgreSQL, translate.Kingbase:
	// 		insertSql = `
	// 			insert into db_change_file(id, created_time, file_sign, file_path, file_type,
	// 				executed_time, executed_status, entry_file)
	// 			values ($1, $2, $3, $4, $5, $6, $7, $8)
	// 		`
	// 	case translate.Oracle:
	// 		insertSql = `
	// 			insert into db_change_file(id, created_time, file_sign, file_path, file_type,
	// 				executed_time, executed_status, entry_file)
	// 			values (:1, :2, :3, :4, :5, :6, :7, :8)
	// 		`
	// 	default:
	// 		insertSql = `
	// 			insert into db_change_file(id, created_time, file_sign, file_path, file_type,
	// 				executed_time, executed_status, entry_file)
	// 				values (?, ?, ?, ?, ?, ?, ?, ?)
	// 		`
	// 	}

	// 	result, err := dbConn.Exec(insertSql, id, nowFmt, fileSum, //
	// 		filePath, "xml", nowFmt, utils.SUCCESS, entryFile)
	// 	if err != nil {
	// 		Sug.Errorf("insert into db_change_file failed, err: %v", err)
	// 		Sug.Errorf("insertSql: %v", insertSql)
	// 		return
	// 	}
	// 	rowsAff, err := result.RowsAffected()
	// 	if err != nil {
	// 		Sug.Errorf("insert into db_change_file RowsAffected failed, err: %v", err)
	// 		return
	// 	}
	// 	Sug.Infof("insert into db_change_file rowsAff: %v, id = %v", rowsAff, *id)
	// 	return
	// }

	// // 再次运行，更新该记录
	// var updateSql string
	// switch DbConfig.DbmsName {
	// case translate.PostgreSQL, translate.Kingbase:
	// 	updateSql = `
	// 			update db_change_file
	// 			set file_sign = $1, executed_time = $2, executed_status = $3
	// 			where id = $4
	// 		`
	// case translate.Oracle:
	// 	updateSql = `
	// 			update db_change_file
	// 			set file_sign = :1, executed_time = :2, executed_status = :3
	// 			where id = :4
	// 		`
	// default:
	// 	updateSql = `
	// 			update db_change_file
	// 			set file_sign = ?, executed_time = ?, executed_status = ?
	// 			where id = ?
	// 		`
	// }

	// result, err := dbConn.Exec(updateSql, fileSum, nowFmt, utils.SUCCESS, id)
	// if err != nil {
	// 	Sug.Errorf("update db_change_file failed, err: %v", err)
	// 	Sug.Errorf("updateSql: %v", updateSql)
	// 	return
	// }
	// rowsAff, err := result.RowsAffected()
	// if err != nil {
	// 	Sug.Errorf("update db_change_file RowsAffected failed, err: %v", err)
	// 	return
	// }
	// Sug.Infof("update db_change_file rowsAff: %v, id = %v", rowsAff, *id)
}

// 检查元数据库表db_change_set的记录
func CheckDbChangeSet(changeSetId *string, runOnChange *string, changeSetSum *string) (string, *DbChangeSet, error) {
	dbChangeSet, err := SelectDbChangeSetById(changeSetId)
	if err != nil {
		// if err == sql.ErrNoRows {
		// 	// 元数据库中无该changeSet的运行记录，可以进行首次运行
		// 	return utils.CS_RUN, nil, nil
		// }
		Sug.Errorf("run SelectDbChangeSetById err: %v changeSetId: %v", err, *changeSetId)
		// 其他异常情况
		return utils.EMPTY, nil, err
	}
	if dbChangeSet == nil {
		// 元数据库中无该changeSet的运行记录，可以进行首次运行
		return utils.CS_RUN, nil, nil
	}
	if *changeSetSum == dbChangeSet.ChangesetSign {
		// 该changeSet已经被执行且【无】变更
		return utils.CS_EXECUTED, dbChangeSet, nil
	} else {
		// 该changeSet已经被执行且【有】变更
		if *runOnChange == utils.TRUE {
			// 配置为需要再次运行
			return utils.CS_RUN, dbChangeSet, nil
		} else {
			// 配置为不允许再次运行
			return utils.CS_CONFLICT, dbChangeSet, nil
		}
	}
}

// 根据changeSetId查询db_change_set表中对应的记录并返回
// dbConn *sql.DB 该数据库连接实例
// changeSetId *string 指定的changeSetId指针
func SelectDbChangeSetById(changeSetId *string) (*DbChangeSet, error) {
	dbChangeSet := DbChangeSet{}

	has, err := db.Engine.Where("id = ?", *changeSetId).Get(&dbChangeSet)
	// Sug.Infof("----**- has %v, dbChangeSet %v err %v", has, dbChangeSet, err)
	if err != nil {
		// sql.ErrNoRows
		return nil, err
	}
	if has {
		return &dbChangeSet, nil
	}
	return nil, nil
	// SELECT * FROM user WHERE name = ? LIMIT 1

	// var selectSql string
	// switch DbConfig.DbmsName {
	// case translate.PostgreSQL, translate.Kingbase:
	// 	selectSql = "select * from db_change_set where id = $1"
	// case translate.Oracle:
	// 	selectSql = "select * from db_change_set where id = :1"
	// default:
	// 	selectSql = "select * from db_change_set where id = ?"
	// }
	// err := dbConn.QueryRow(selectSql, changeSetId).Scan(&dbChangeSet.Id, &dbChangeSet.Author, //
	// 	&dbChangeSet.FileName, &dbChangeSet.CreatedTime, &dbChangeSet.ExecutedTime, //
	// 	&dbChangeSet.ExecutedStatus, &dbChangeSet.ExecutedOrder, &dbChangeSet.ExecType, //
	// 	&dbChangeSet.ChangesetComment, &dbChangeSet.ChangesetSign, //
	// 	&dbChangeSet.LiquigoVersion)
	// if err != nil {
	// 	// sql.ErrNoRows
	// 	// Sug.Errorf("select db_change_set err %v\nsql: %v\n", err, selectSql)
	// 	return nil, err
	// }
	// return &dbChangeSet, nil
}

// 创建元数据表[db_change_file,db_change_set]，如果不存在的话
// dbConn *sql.DB 该数据库连接实例
func CreateMetaTable() error {
	if err := checkMetaTableExist(); err != nil {
		// 表不存在
		if err = createMetaTable(); err != nil {
			Sug.Errorf("createMetaTable err %v", err)
			return err
		}
	}
	return nil
}

// 检查元数据表[db_change_file]是否存在，如果不存在则返回err
// dbConn *sql.DB 该数据库连接实例
func checkMetaTableExist() error {
	dbChangeFile := DbChangeFile{}
	_, err := db.Engine.Where("id = ?", "None").Get(&dbChangeFile)
	if err != nil {
		// db_change_file表不存在，同时表示db_change_set表也不存在
		// fmt.Printf("checkMetaTableExist err: %v\n", err)
		return err
	}
	return nil

	// selectSql := "select * from db_change_file where id = 'None'"
	// rows, err := dbConn.Query(selectSql)
	// if err != nil {
	// 	// db_change_file表不存在，同时表示db_change_set表也不存在
	// 	// fmt.Printf("checkMetaTableExist err: %v\n", err)
	// 	return err
	// }
	// rows.Close()
	// return nil
}

// 创建元数据表[db_change_file,db_change_set]，如果不存在的话
// dbConn *sql.DB 该数据库连接实例
func createMetaTable() error {
	xmlDoc := etree.NewDocument()
	if err := xmlDoc.ReadFromString(META_CHANGE_SET); err != nil {
		// 解析元数据库表的XML片段失败
		Sug.Errorf("Failed to parse XML fragment of meta table, err: %v", err)
		return err
	}
	root := xmlDoc.SelectElement("changeSet")
	entityElems := root.ChildElements()
	for _, entityElem := range entityElems {
		sql, err := translate.GetSql(DbConfig, entityElem)
		if err != nil {
			// 翻译元数据库表元素为sql语句失败
			Sug.Errorf("Failed to translate meta table element into SQL statement, err: %v", err)
			return err
		}
		if DbConfig.DbmsName == translate.Dameng || DbConfig.DbmsName == translate.Oracle {
			// 达梦和Oracle数据库，不能批量执行sql，只能以分号拆分sql逐个运行
			sqlArr := strings.Split(sql, utils.SEMICOLON)
			for _, singleSql := range sqlArr {
				if strings.Trim(singleSql, utils.BLANK_CHARS) == utils.EMPTY {
					continue
				}
				if _, err = db.Engine.Exec(singleSql); err != nil {
					// 执行元数据库表sql语句失败
					Sug.Errorf("Failed to execute meta table SQL statement, err: %v", err)
					Sugf.Errorf("\n%v", singleSql)
					return err
				}
			}
		} else {
			// 非达梦和Oracle数据库，可以批量执行sql
			if _, err = db.Engine.Exec(sql); err != nil {
				// 执行元数据库表sql语句失败
				Sug.Errorf("Failed to execute meta table SQL statement, err: %v", err)
				Sugf.Errorf("sql: \n%v", sql)
				return err
			}
		}

	}
	return nil
}

// 新增插入指定changeSetId的DbChangeSet记录，仅用于前置条件判断异常时标记为MARK_RAN
// 如果已经存在该记录，则不作处理
func InsertDbChangeSetForMarkRun(changeSetId *string, //
	author *string, changeSetFile *string, executedOrder *int, changeSet *etree.Element) {

	dbChangeSet, err := SelectDbChangeSetById(changeSetId)
	if dbChangeSet != nil {
		// 有记录
		return
	}
	if err != nil {
		// 有异常
		Sug.Errorf("run SelectDbChangeSetById err: %v changeSetId: %v", err, *changeSetId)
		return
	}
	// 元数据库中无该changeSet的运行记录，则新增插入
	// 开启事务操作
	// dbTx, errTxBegin := dbConn.Begin()
	// if errTxBegin != nil {
	// 	// 开启数据库事务失败，也可能是不支持事务
	// 	Sug.Errorf("Failed to open database transaction, errTxBegin: %v", errTxBegin)
	// 	panic(errTxBegin)
	// }
	session := db.Engine.NewSession()
	defer session.Close()
	// add Begin() before any action
	if errTxBegin := session.Begin(); errTxBegin != nil {
		// 开启数据库事务失败，也可能是不支持事务
		Sug.Errorf("Failed to open database transaction, errTxBegin: %v", errTxBegin)
		panic(errTxBegin)
	}

	changeSetSum := utils.EMPTY
	executedStatus := utils.PC_MARK_RAN
	InsertDbChangeSet(session, changeSetId, author, changeSetFile, &executedStatus, executedOrder, &changeSetSum, changeSet)
	// 提交事务
	errTxCommit := session.Commit()
	if errTxCommit != nil {
		Sug.Errorf("Failed to commit database transaction, changeSetId(%v), errTxCommit: %v", changeSetId, errTxCommit)
		errTxRollback := session.Rollback()
		if errTxRollback != nil {
			Sug.Errorf("Failed to rollback database transaction, changeSetId(%v), errTxRollback: %v", changeSetId, errTxRollback)
		}
		panic(errTxCommit)
	}
}

// 新增插入DbChangeSet记录或更新指定changeSetId的DbChangeSet记录
func InsertOrUpdateDbChangeSet(session *xorm.Session, dbChangeSet *DbChangeSet, changeSetId *string, //
	author *string, changeSetFile *string, executedOrder *int, changeSetSum *string, changeSet *etree.Element) {
	executedStatus := utils.SUCCESS
	if dbChangeSet == nil {
		InsertDbChangeSet(session, changeSetId, author, changeSetFile, &executedStatus, //
			executedOrder, changeSetSum, changeSet)
	} else {
		UpdateDbChangeSet(session, changeSetId, &executedStatus, changeSetSum, changeSet)
	}
}

// 新增插入DbChangeSet记录
func InsertDbChangeSet(session *xorm.Session, changeSetId *string, author *string, changeSetFile *string, //
	executedStatus *string, executedOrder *int, changeSetSum *string, changeSet *etree.Element) {
	nowFmt := time.Now().Format(utils.YMDHMS)

	var changeSetComment string
	commentElem := changeSet.SelectElement("comment")
	if commentElem != nil {
		// changeSet comment
		changeSetComment = translate.GetCommentText(nil, commentElem)
	}
	*executedOrder++
	// // 首次运行，插入新记录
	// var insertSql string
	// switch DbConfig.DbmsName {
	// case translate.PostgreSQL, translate.Kingbase:
	// 	insertSql = `
	// 			insert into db_change_set(id, author, file_name, created_time,
	// 				executed_time, executed_status, executed_order, exec_type, changeset_comment,
	// 				changeset_sign, liquigo_version)
	// 			values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
	// 		`
	// case translate.Oracle:
	// 	insertSql = `
	// 			insert into db_change_set(id, author, file_name, created_time,
	// 				executed_time, executed_status, executed_order, exec_type, changeset_comment,
	// 				changeset_sign, liquigo_version)
	// 			values (:1, :2, :3, :4, :5, :6, :7, :8, :9, :10, :11)
	// 		`
	// default:
	// 	insertSql = `
	// 			insert into db_change_set(id, author, file_name, created_time,
	// 				executed_time, executed_status, executed_order, exec_type, changeset_comment,
	// 				changeset_sign, liquigo_version)
	// 				values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
	// 		`
	// }

	// 首次运行，插入新记录
	dbChangeSet := DbChangeSet{Id: *changeSetId, Author: *author, FileName: *changeSetFile, //
		CreatedTime: nowFmt, ExecutedTime: nowFmt, ExecutedStatus: *executedStatus, //
		ExecutedOrder: *executedOrder, ExecType: utils.CS_EXECUTED, //
		ChangesetComment: changeSetComment, ChangesetSign: *changeSetSum, //
		LiquigoVersion: config.LiquigoVersion}
	affected, err := session.Insert(&dbChangeSet)
	if err != nil {
		Sug.Errorf("insert into db_change_set failed, affected: %v, err: %v", affected, err)
		Sug.Errorf("dbChangeSet: %v", dbChangeSet)
		return
	}
	Sug.Infof("insert into db_change_set affected: %v, id: %v", affected, *changeSetId)

	// result, err := dbTx.Exec(insertSql, changeSetId, author, changeSetFile, //
	// 	nowFmt, nowFmt, executedStatus, *executedOrder, utils.CS_EXECUTED, //
	// 	changeSetComment, changeSetSum, utils.LIQUIGO_VERSION)
	// if err != nil {
	// 	Sug.Errorf("insert into db_change_set failed, err: %v", err)
	// 	Sug.Errorf("insertSql: %v", insertSql)
	// 	return
	// }
	// rowsAff, err := result.RowsAffected()
	// if err != nil {
	// 	Sug.Errorf("insert into db_change_set RowsAffected failed, err: %v", err)
	// 	return
	// }
	// Sug.Infof("insert into db_change_set rowsAff: %v, id = %v", rowsAff, *changeSetId)
}

// 更新指定changeSetId的DbChangeSet记录
func UpdateDbChangeSet(session *xorm.Session, changeSetId *string, executedStatus *string, changeSetSum *string, changeSet *etree.Element) {
	nowFmt := time.Now().Format(utils.YMDHMS)

	var changeSetComment string
	commentElem := changeSet.SelectElement("comment")
	if commentElem != nil {
		// changeSet comment
		changeSetComment = translate.GetCommentText(nil, commentElem)
	}

	// 再次运行，更新该记录
	// var updateSql string
	// switch DbConfig.DbmsName {
	// case translate.PostgreSQL, translate.Kingbase:
	// 	updateSql = `
	// 			update db_change_set
	// 			set executed_time = $1, executed_status = $2, exec_type = $3,
	// 				changeset_comment = $4, changeset_sign = $5, liquigo_version = $6
	// 			where id = $7
	// 		`
	// case translate.Oracle:
	// 	updateSql = `
	// 			update db_change_set
	// 			set executed_time = :1, executed_status = :2, exec_type = :3,
	// 				changeset_comment = :4, changeset_sign = :5, liquigo_version = :6
	// 			where id = :7
	// 		`
	// default:
	// 	updateSql = `
	// 			update db_change_set
	// 			set executed_time = ?, executed_status = ?, exec_type = ?,
	// 				changeset_comment = ?, changeset_sign = ?, liquigo_version = ?
	// 			where id = ?
	// 		`
	// }

	dbChangeSet := DbChangeSet{ExecutedTime: nowFmt, ExecutedStatus: *executedStatus, ExecType: utils.CS_RERAN, //
		ChangesetComment: changeSetComment, ChangesetSign: *changeSetSum, LiquigoVersion: config.LiquigoVersion}
	affected, err := session.ID(*changeSetId).Update(&dbChangeSet)
	// affected, err := db.Engine.Exec(updateSql, fileSum, nowFmt, utils.SUCCESS, id)
	if err != nil {
		Sug.Errorf("update db_change_set failed, affected: %v, err: %v", affected, err)
		Sug.Errorf("dbChangeSet.id: %v", *changeSetId)
		return
	}
	Sug.Infof("update db_change_set affected: %v, id = %v", affected, *changeSetId)

	// result, err := dbTx.Exec(updateSql, nowFmt, executedStatus, utils.CS_RERAN, //
	// 	changeSetComment, changeSetSum, utils.LIQUIGO_VERSION, changeSetId)
	// if err != nil {
	// 	Sug.Errorf("update db_change_set failed, err: %v", err)
	// 	Sug.Errorf("updateSql: %v", updateSql)
	// 	return
	// }
	// rowsAff, err := result.RowsAffected()
	// if err != nil {
	// 	Sug.Errorf("update db_change_set RowsAffected failed, err: %v", err)
	// 	return
	// }
	// Sug.Info("update db_change_set rowsAff: %v, id = %v", rowsAff, *changeSetId)
}
